State = function(){
	this.state = {};
	this.callback = null;
	this.scope = null;
	this.notify = function(){
		if(this.callback) this.callback.call(this.scope, this);
	}
	this.setStateCallback = function(callback, scope){
		this.callback = callback;
		this.scope = scope;
		this.notify();
	}
	this.submitValue = function(key, value){
		if(value == null || value == undefined){
			delete this.state[key];
		}
		else{
			this.state[key] = value;
		}
		this.notify();
	}
	this.submitDelta = function(delta){
		for(var key in delta){
			this.state[key] = delta[key]
		}
		this.notify();
	}
	this.get = function(key){
		if(this.state[key] == undefined || this.state[key] == null) return '';
		return this.state[key];
	}
}

Service = function(savedState){
	var _state = new State();
	var query = savedState;
	var _this = this;
	var URL_PREFIX = '../service/';
	this.isHost = false;
	this.baskStep = {
		'VolnaSite0': 'service',
		'VolnaSite1': 'token',
		'VolnaSite2': 'menuId',
		'VolnaSite': 'title',
		'GDocs0': 'service',
		'GDocs1': 'token',
		'GDocs': 'title',
		'Blogger0': 'service',
		'Blogger1': 'token',
		'Blogger2': 'blogId',
		'Blogger': 'title',
		'Html0': 'service'
	}
	var currentService = '';
	var currentStep = 0;
	var publishHandler = function(event, bla, bla1, msg){
		if(!msg || typeof msg !== 'string'){
			msg = _('Wave successfully exported.');
		}
		if(window.parent && window != window.parent && window.parent.postMessage){
			window.parent.postMessage('[{"action": "closeGwextWnd"}]', 'https://wave.google.com/');
		}
		else{
			alert(msg);
		}
	}
	var uiConstants = {
		'okButton': _('Ok'),
		'cancelButton': _('Cancel'),
		'authorizeButton': _('Authorize'),
		'updateButton': _('Update'),
		'publishButton': _('Publish'),
		'backButton': _('Back'),
		'fixButton': _('Fix')
	}
	this.steps = {
		'default': function(){
			$('#ok').bind('click', {_this: this},
				function(e){
					_state.submitValue('service', $('#selectService').val());
				}
			);
		},
		'Blogger0': function(serviceName){
			if(!serviceName) serviceName = 'Blogger'
			popupWnd = new Popup(URL_PREFIX + serviceName + '/authCheck?' +
					'locale=' + encodeURIComponent(query['locale']) +
					'&waveId=' + encodeURIComponent(query['waveId']),
				function() {
					var callback = function(data){
						_state.submitValue('token', data['token']);
					}
					$.ajax({
						url: URL_PREFIX + serviceName + '/getAccessToken?' +
								'locale=' + encodeURIComponent(query['locale']) +
								'&waveId=' + encodeURIComponent(query['waveId']),
						dataType: 'json',
						async: false,
						success: callback,
						error: processError
					});
				},
				this);
			$('#oauthpopup').bind('click', function(e){
				popupWnd.open();
			});
		},
		'Blogger1': function(){
			var callback = function(data){
				_state.submitValue('blogs', {'blogs': data['blogs']});
			}
			$('#update').bind('click', function(){
				$.ajax({
					url: URL_PREFIX + 'Blogger/getBlogList?' +
							'locale=' + encodeURIComponent(query['locale']) +
							'&waveId=' + encodeURIComponent(query['waveId']) + '&' +  _state.get('token'),
					dataType: 'json',
					async: false,
					success: callback,
					error: processError
				});
			});
			if(!_state.get('blogs')){
				$('#ok').attr('class', 'button-disabled');
				$('#update').trigger('click');
				return;
			}
			$('#ok').attr('class', 'button');
			$('#ok').bind('click', function(){
				_state.submitValue('blogId', $('#blogs').val());
			});
		},
		'Blogger2': function(){
			var callback = function(data){
				_state.submitValue('posts', {'posts': data['posts']});
			}
			$('#update').bind('click', function(){
				$.ajax({
					url: URL_PREFIX + 'Blogger/getPostList?' +
							'locale=' + encodeURIComponent(query['locale']) +
							'&waveId=' + encodeURIComponent(query['waveId']) +
							'&blogId=' + _state.get('blogId') +
							'&' +  _state.get('token'),
					dataType: 'json',
					async: false,
					success: callback,
					error: processError
				});
			})
			if(!_state.get('posts')){
				$('#ok').attr('class', 'button-disabled');
				$('#update').trigger('click');
				return;
			}
			$('#ok').attr('class', 'button');
			$('#ok').bind('click', function(){
				_state.submitDelta({
					'postId': $('#posts').val(),
					'link': '#'
				});
			});
		},
		'Blogger': function(){
			$('#bloggerPublish').bind('click', function(){
				if(_state.get('blogId')){
					var postId = _state.get('postId');
					if(!postId) postId = '';
					if(!postId || window.confirm(_("Are you sure you want to replace your data?"))){
						$.ajax({
							url: URL_PREFIX + 'Blogger/publishPost?' +
									'locale=' + encodeURIComponent(query['locale']) +
									'&waveId=' + encodeURIComponent(query['waveId']) +
									'&waveletId=' + encodeURIComponent(query['waveletId']) +
									'&blipId=' + encodeURIComponent(query['blipId']) +
									'&hash=' + encodeURIComponent(query['hash']) +
									'&blogId=' + _state.get('blogId') +
									'&postId=' + postId +
									'&' + _state.get('token'),
							dataType: 'json',
							async: false,
							success: publishHandler,
							error: processError
						});
					}
				}
			});
		},
		'GDocs0': function(){
			this.steps['Blogger0'].call(this, 'GDocs');
		},
		'GDocs1': function(){
			// getting document list
			var callback = function(data){
				_state.submitValue('gdocs', {'gdocs': data['gdocs']});
			}
			$('#update').bind('click', function(){
				$.ajax({
					url: URL_PREFIX + 'GDocs/getDocList?' +
							'locale=' + encodeURIComponent(query['locale']) +
							'&waveId=' + encodeURIComponent(query['waveId']) +
							'&' + _state.get('token'),
					dataType: 'json',
					async: false,
					success: callback,
					error: processError
				});
			})
			if(!_state.get('gdocs')){
				$('#ok').attr('class', 'button-disabled');
				$('#update').trigger('click');
				return;
			}
			$('#ok').attr('class', 'button');
			$('#ok').bind('click', function(){
				_state.submitDelta({
					'gdocId': $('#gdocs').val(),
					'link': '#'
				});
			});
		},
		'GDocs': function(){
			// publishing document
			$('#postDoc').bind('click', function(){
				var gdocId = _state.get('gdocId');
				if(!gdocId) gdocId = '';
				if(!gdocId || window.confirm(_("Are you sure you want to replace your data?"))){
					$.ajax({
						url: URL_PREFIX + 'GDocs/postDoc?' +
								'locale=' + encodeURIComponent(query['locale']) +
								'&waveId=' + encodeURIComponent(query['waveId']) +
								'&waveletId=' + encodeURIComponent(query['waveletId']) +
								'&blipId=' + encodeURIComponent(query['blipId']) +
								'&hash=' + encodeURIComponent(query['hash']) +
								'&gdocId=' + gdocId +
								'&' + _state.get('token'),
						dataType: 'json',
						async: false,
						success: publishHandler,
						error: processError
					});
				}
			});
		},
		'VolnaSite0': function(){
			this.steps['Blogger0'].call(this, 'VolnaSite');
		},
		'VolnaSite1': function(){
			var url = URL_PREFIX + 'VolnaSite/getMenuList?' +
					'locale=' + encodeURIComponent(query['locale']) +
					'&waveId=' + encodeURIComponent(query['waveId']) + 
					'&token=' +  _state.get('token');
			var menuProcessor = function(obj, shift){
				var menu = {};
				menu['id'] = obj['id'];
				menu['title'] = shift + '/' + obj['name'];
				var menus = [menu];
				for(var i in obj['children']){
					menus = menus.concat(menuProcessor(obj['children'][i], shift + '---'));
				}
				return menus;
			}
			var callback = function(data){
				var menus = []
				for(var i in data['menutree']){
					menus = menus.concat(menuProcessor(data['menutree'][i], ''));
				}
				_state.submitValue('menus', {'menus': menus});
			}
			$('#update').bind('click', function(){
				$.ajax({
					url: url,
					dataType: 'json',
					async: false,
					success: callback,
					error: processError
				});
			});
			if(!_state.get('menus')){
				$('#ok').attr('class', 'button-disabled');
				$('#update').trigger('click');
				return;
			}
			$('#ok').attr('class', 'button');
			$('#ok').bind('click', function(){
				_state.submitValue('menuId', $('#menus').val());
			});
		},
		'VolnaSite2': function(){
			var callback = function(data){
				_state.submitValue('docs', {'docs': data});
			}
			var menuId = _state.get('menuId');
			var url = URL_PREFIX + 'VolnaSite/getDocList?' +
					'locale=' + encodeURIComponent(query['locale']) +
					'&waveId=' + encodeURIComponent(query['waveId']) + 
					'&menuId=' + (menuId == '###' ? '' : menuId) + 
					'&token=' + _state.get('token');
			$('#update').bind('click', function(){
				$.ajax({
					url: url,
					dataType: 'json',
					async: false,
					success: callback,
					error: processError
				});
			})
			if(!_state.get('docs')){
				$('#ok').attr('class', 'button-disabled');
				$('#update').trigger('click');
				return;
			}
			$('#ok').attr('class', 'button');
			$('#ok').bind('click', function(){
				_state.submitDelta({
					'docId': $('#docs').val(),
					'link': '#'
				});
			});
		},
		'VolnaSite': function(){
			$('#volnaSitePublish').bind('click', function(){
				var menuId = _state.get('menuId'); 
				if(menuId){
					var docId = _state.get('docId');
					if(!docId) docId = '';
					if(!docId || window.confirm(_("Are you sure you want to replace your data?"))){
						$.ajax({
							url: URL_PREFIX + 'VolnaSite/postDoc?' +
									'locale=' + encodeURIComponent(query['locale']) +
									'&waveId=' + encodeURIComponent(query['waveId']) +
									'&waveletId=' + encodeURIComponent(query['waveletId']) +
									'&blipId=' + encodeURIComponent(query['blipId']) +
									'&hash=' + encodeURIComponent(query['hash']) +
									'&menuId=' + (menuId == '###' ? '' : menuId) +
									'&docId=' + docId + '&token=' + _state.get('token'),
							dataType: 'json',
							async: false,
							success: publishHandler,
							error: processError
						});
					}
				}
			});
		},
		'Html0': function(){
			this.steps['Blogger0'].call(this, 'Html');
		},
		'Html': function(){
			$('#htmlPublish').bind('click', function(){
				$.ajax({
					url: URL_PREFIX + 'Html/postDoc?' +
							'locale=' + encodeURIComponent(query['locale']) +
							'&waveId=' + encodeURIComponent(query['waveId']) +
							'&waveletId=' + encodeURIComponent(query['waveletId']) +
							'&blipId=' + encodeURIComponent(query['blipId']) +
							'&hash=' + encodeURIComponent(query['hash']) +
							'&token=' + _state.get('token')+
							'&userId=' + encodeURIComponent(_state.get('userId')),
					dataType: 'json',
					async: false,
					success: publishHandler,
					error: processError
				});
			});
		}
	}
	
	// order in which states appear
	this.states = {
		'Blogger': ['service', 'token', 'blogs', 'blogId', 'posts', 'postId', 'title', 'link'],
		'GDocs': ['service', 'token', 'gdocs', 'gdocId', 'title', 'link'],
		'VolnaSite': ['service', 'token', 'menus', 'menuId', 'docs', 'docId', 'title', 'link'],
		'Html': ['service', 'token', 'title', 'link']
	}
	
	// state update processor
	this.processState = function(state){
		var service = state.get('service'); 
		if(!service){
			this.renderCurrentStep('default')
			return;
		}
		currentService = service;
		if(service == 'Blogger'){
			if(!state.get('link')){
				var step = 0;
				if(state.get('token')){
					step++;
					if(state.get('blogId')){
						step++;
					}
				}
				this.renderCurrentStep(service, step);
			}
			else{
				this.renderCurrentStep(service);
			}
			return;
		}
		if(service == 'GDocs'){
			if(!state.get('link')){
				var step = 0;
				if(state.get('token')){
					step++;
				}
				this.renderCurrentStep(service, step)
			}
			else{
				this.renderCurrentStep(service);
			}
			return;
		}
		if(service == 'VolnaSite'){
			if(!state.get('link')){
				var step = 0;
				if(state.get('token')){
					step++;
					if(state.get('menuId')){
						step++;
					}
				}
				this.renderCurrentStep(service, step);
			}
			else{
				this.renderCurrentStep(service);
			}
			return;
		}
		if(service == 'Html'){
			if(!state.get('token')){
				var step = 0;
				this.renderCurrentStep(service, step);
			}
			else{
				this.renderCurrentStep(service);
			}
			return;
		}
	}

	this.clearState = function(stateToClear){
		var state = _state;
		var delta = {}
		for(var i = 0, foundState = false; i < this.states[currentService].length; i++){
			if(this.states[currentService][i] == stateToClear) foundState = true;
			if(foundState){
				delta[this.states[currentService][i]] = ''
			}
		}
		state.submitDelta(delta)
	}

	var processError = function(jqXHR, textStatus, errorThrown){
		if(textStatus && textStatus == 'timeout'){
			$('#message').html(_('Timeout error.') + ' ' + _('Try again later.'));
			return;
		}
		if(textStatus && textStatus == 'parsererror'){
			$('#message').html(_('Parse error.') + ' ' + _('Try again later.'));
			return;
		}
		var stateToClear = '';
		var status = jqXHR.status;
		if(status == 500){
			var message = _('Internal server error.') + ' ' + _('Try again later.');
			$('#message').html(message);
			return;
		}
		var message = ''
		if(currentService == 'Blogger'){
			switch(status){
			case 401:
				stateToClear = 'token';
				message = _('Token is invalid.') + ' '; 
				break;
			case 400:
				stateToClear = 'blogs'
				message = _('Blog is invalid.') + ' ';
				break;
			case 404:
				stateToClear = 'posts';
				message = _('Document not found.') + ' ';
			}
		}else if(currentService == 'GDocs'){
			switch(status){
			case 401:
				stateToClear = 'token'
				message = _('Token is invalid.') + ' '; 
				break;
			case 404:
			case 400:
				stateToClear = 'gdocs';
				message = _('Document not found.') + ' ';
				break;
			}
		}else if(currentService == 'VolnaSite.'){
			switch(status){
			case 401:
				stateToClear = 'token';
				message = _('Token is invalid.') + ' ';
				break;
			case 400:
				stateToClear = 'menus';
				message = _('Menu is invalid.') + ' ';
				break;
			case 404:
				stateToClear = 'docs';
				message = _('Document not found.') + ' ';
				break;
			}
		}
		$('#message').html(message);
		$('#controls').children().remove();
		$('#fixButonTemplate').tmpl(uiConstants).appendTo('#controls');
		$('#fix').bind('click', function(){
			service.clearState(stateToClear);
		});
	}
	
	this.templateParams = {
		'default': function(){
			var params = {
				'message': _('Select service.'),
				'services': [{
					'id': 'Blogger',
					'title': _('Blogger')
				},{
					'id': 'GDocs',
					'title': _('Google Documents')
				},{
					'id': 'VolnaSite',
					'title': _('Project Volna Site')
				},{
					'id': 'Html',
					'title': _('Raw HTML')
				}]
			};
			return params;
		},
		'Blogger0': function(){
			return {
				'message': _('Authorize on Blogger.com.')
			}
		},
		'Blogger1': function(){
			var blogs = _state.get('blogs') || {};
			blogs['message'] = _('Select blog.');
			blogs['updateText'] = _('refresh blogs');
			return blogs;
		},
		'Blogger2': function(){
			var posts = _state.get('posts') || {};
			posts['message'] = _('Select post.');
			posts['updateText'] = _('refresh posts');
			posts['newPost'] = _('<add new post>')
			return posts;
		},
		'Blogger': function(){
			return {
				'link': _state.get('link'),
				'title': _state.get('title'),
				'message': _('Blogger publish is ready.')
			};
		},
		'GDocs0': function(){
			return {
				'message': _('Authorize on Goolge Docs.')
			}
		},
		'GDocs1': function(){
			var gdocs = _state.get('gdocs') || {};
			gdocs['message'] = _('Select gdoc.');
			gdocs['updateText'] = _('refresh docs');
			gdocs['newGDoc'] = _('<add new document>');
			return gdocs;
		},
		'GDocs': function(){
			gdocs = this.templateParams['Blogger'].call(this);
			gdocs['message'] = _('GDocs publish is ready.')
			return gdocs;
		},
		'VolnaSite0': function(){
			return {
				'message': $.gt.gettext('Authorize on projectvolna.com.')
			}
		},
		'VolnaSite1': function(){
			var menus = _state.get('menus') || {};
			menus['message'] = $.gt.gettext('Select menu.');
			menus['updateText'] = _('refresh menus');
			return menus;
		},
		'VolnaSite2': function(){
			var docs = _state.get('docs') || {};
			docs['message'] = $.gt.gettext('Select document.');
			docs['updateText'] = _('refresh docs');
			docs['newDoc'] = _('<add new document>');
			return docs;
		},
		'VolnaSite': function(){
			params = this.templateParams['GDocs'].call(this);
			params['message'] = _('VolnaSite publish is ready.');
			return params;
		},
		'Html0': function(){
			return {
				'message': _('Authorize yourself.')
			}
		},
		'Html': function(){
			gdocs = this.templateParams['Blogger'].call(this);
			gdocs['message'] = _('Html publish ready.')
			return gdocs;
		}
	}
	
	this.getTemplateParams = function(service){
		if(!this.templateParams[service]) return {};
		return this.templateParams[service].call(this);
	}
	
	this.renderCurrentStep = function(serviceToRender, step, message){
		if(step == undefined) step = '';
		if(step < 0){
			serviceToRender = 'default';
			step = '';
		}
		currentStep = step;
		$('#content').children().remove();
		var params = this.getTemplateParams(serviceToRender + step);
		params['service'] = serviceToRender;
		if(message) params['message'] = message;
		$.extend(params, uiConstants);
		if(!step){
			params['linkLabel'] = _('Link to your post:');
		}
		$('#face').tmpl(params).appendTo('#content');
		$('#' + serviceToRender + step).tmpl(params).appendTo('#controls');
		if(typeof(step) == 'number'){
			$('#backBtnContainer').tmpl(params).appendTo('#controls');
			$('#backBtn').bind('click', {},
				function(){
					service.clearState(service.baskStep[serviceToRender+step]);
				}
			)
		}
		if(this.steps[serviceToRender + step]) this.steps[serviceToRender + step].call(this);
	}
	_state.submitDelta(savedState);
	_state.setStateCallback(this.processState, this);
}
